#include "judgment.h"
#include <cstdio>
#include <cstdlib>
#include <cassert>

Judgment::Judgment()
{
}

Judgment::~Judgment()
{
}

/** Interface CHN Rule Judgment **/
pair<int,int> Judgment::moyoCalculateCHN(int eog_board[][DIMENSION])
{
    coordinate coo;

    init(1);
    copyBoard(eog_board);

    for(register int i=1; i<DIMENSION-1; i++)
    {
        for(register int j=1; j<DIMENSION-1; j++)
        {
            if(board[i][j]==VOID)
            {
                checked[i][j]=0;
            }
        }
    }

    for(register int i=1; i<DIMENSION-1; i++)
    {
        for(register int j=1; j<DIMENSION-1; j++)
        {
            if(checked[i][j]==0)
            {
                init_getVoidBlock(i,j); //在这里调用递归函数的调用函数
            }
        }
    }

    /** 填子结束后进行数子工作 **/
    for(register int i=1; i<DIMENSION-1; i++)
    {
        for(register int j=1; j<DIMENSION-1; j++)
        {
            if(board[i][j]==BLACK) moyoBlack++;
            if(board[i][j]==WHITE) moyoWhite++;
        }
    }

    coo.first = moyoBlack; coo.second = moyoWhite;
    return coo;
}

/** Interface INFLUENCE Model Judgment **/
pair<int,int> Judgment::moyoCalculateINFLUENCE(const int temp_board[][DIMENSION])
{
    init(2);
    copyBoard(temp_board); //保持temp_board的const性
                           //将temp_board的数据赋值给board

    /** 在此之前简单的(必然)死活的判断有其必要性 **/
    /** 死活判断原则: 0手活 1手活 2手活 ??? **/
    judgment_influenceCalc(board); //board在这里被修改

    //对board进行"封闭"
    for(register int x=1; x<DIMENSION-1; x++)
    {
        for(register int y=1; y<DIMENSION-1; y++)
        {
            if(board[x][y] == VOID)
            {
                if(influence[x][y] >  BOUND) board[x][y] = BLACK;
                if(influence[x][y] < -BOUND) board[x][y] = WHITE;
            }
        }
    }

    //对board进行操作, 剔除单官位置算作目数的点
    identifyPublic(temp_board);

    //调用数子规则函数得出最终形式判断结果
    return moyoCalculateCHN(board);
}

/** Interface output textBoard form use tab symbols **/
/** 制表符为全角长为2个字符的字符串 **/
void Judgment::txtBoard_printf(const int temp_board[][DIMENSION])
{
    for(register int y=1; y<DIMENSION-1; y++)
    {
        for(register int x=1; x<DIMENSION-1; x++)
        {
            if(temp_board[x][y] == BLACK) printf("●");
            else if(temp_board[x][y] == WHITE) printf("○");
            else if(temp_board[x][y] == VOID)
            {
                if(x==1 && y==1) printf("┌");
                else if(x==1 && y==DIMENSION-2) printf("└");
                else if(x==DIMENSION-2 && y==1) printf("┐");
                else if(x==DIMENSION-2 && y==DIMENSION-2) printf("┘");
                else if(x==1 && y>1 && y<DIMENSION-2) printf("├");
                else if(x==DIMENSION-2 && y>1 && y<DIMENSION-2) printf("┤");
                else if(y==1 && x>1 && x<DIMENSION-2) printf("┬");
                else if(y==DIMENSION-2 && x>1 && x<DIMENSION-2) printf("┴");
                else printf("┼");
            }
            if(x == DIMENSION-2) printf("\n");
        }
    }
}

bool Judgment::txtBoard_fprintf(const int temp_board[][DIMENSION], const char* fileName)
{
    FILE * pfile;
    pfile = fopen(fileName, "w");
    if(pfile == NULL) return false;

    for(register int y=1; y<DIMENSION-1; y++)
    {
        for(register int x=1; x<DIMENSION-1; x++)
        {
            if(temp_board[x][y] == BLACK) fprintf(pfile, "●");
            else if(temp_board[x][y] == WHITE) fprintf(pfile, "○");
            else if(temp_board[x][y] == VOID)
            {
                if(x==1 && y==1) fprintf(pfile, "┌");
                else if(x==1 && y==DIMENSION-2) fprintf(pfile, "└");
                else if(x==DIMENSION-2 && y==1) fprintf(pfile, "┐");
                else if(x==DIMENSION-2 && y==DIMENSION-2) fprintf(pfile, "┘");
                else if(x==1 && y>1 && y<DIMENSION-2) fprintf(pfile, "├");
                else if(x==DIMENSION-2 && y>1 && y<DIMENSION-2) fprintf(pfile, "┤");
                else if(y==1 && x>1 && x<DIMENSION-2) fprintf(pfile, "┬");
                else if(y==DIMENSION-2 && x>1 && x<DIMENSION-2) fprintf(pfile, "┴");
                else fprintf(pfile, "┼");
            }
            if(x == DIMENSION-2) fprintf(pfile, "\n");
        }
    }
    return true;
}

/** private functions **/
inline void Judgment::init(int funcNum)
{
    switch(funcNum)
    {
        case 1: //Judgment::moyoCalculateCHN
        {
            on_off = false;
            belongsTo = GRID;
            moyoBlack = 0;
            moyoWhite = 0;
            for(register int i=1; i<DIMENSION-1; i++)
            {
                for(register int j=1; j<DIMENSION-1; j++)
                {
                    //board[i][j] = VOID;
                    count[i][j] = 0;
                    checked[i][j] = 1;
               }
            }
            for(register int i=0; i<DIMENSION; i++)
            {
                board[0][i] = GRID;
                board[DIMENSION-1][i] = GRID;
                board[i][0] = GRID;
                board[i][DIMENSION-1] = GRID;
            }
            if(!tempSeries.empty()) tempSeries.clear();
            break;
        }

        case 2: //influence judgment
        {
            on_off = false;
            for(register int i=1; i<DIMENSION-1; i++)
            {
                for(register int j=1; j<DIMENSION-1; j++)
                {
                    //board[i][j] = VOID;
                    count[i][j] = 0;
                    checked[i][j] = 0;
               }
            }
            for(register int i=0; i<DIMENSION; i++)
            {
                board[0][i] = GRID;
                board[DIMENSION-1][i] = GRID;
                board[i][0] = GRID;
                board[i][DIMENSION-1] = GRID;
            }
        }
    }
}

inline void Judgment::copyBoard(const int temp_board[][DIMENSION])
{
    for(register int i=1; i<DIMENSION-1; i++)
    {
        for(register int j=1; j<DIMENSION-1; j++)
        {
            board[i][j] = temp_board[i][j];
        }
    }
}

int Judgment::getVoidBlock(int x,int y)
{
    coordinate coo;

    if(board[x][y] == VOID)
    {
        if (!on_off){ //静态变量归零代码
            for (register int i=1;i<DIMENSION-1;i++){
                for (register int j=1;j<DIMENSION-1;j++){
                    count[i][j]=0;
                }
            }
            tempSeries.clear(); //静态变量vector<pair<int,int>>的清零工作
            on_off=true; //开关关闭, 因为递归时不需要归零
            belongsTo=GRID;
        }

        count[x][y] = 1; //将目前的位置标记为计算过的位置(防止重复递归)
        checked[x][y] = 1; //将此空点标记为已经检查过了

        coo.first = x; coo.second = y;
        tempSeries.push_back(coo);

        /* 统计该坐标下一格位置 */
        if(board[x][y+1]==VOID && count[x][y+1]==0){
            getVoidBlock(x,y+1);
        }
        else
        {
            if(belongsTo!=VOID)
            {
                if(board[x][y+1]==BLACK)
                {
                    if(belongsTo==GRID) belongsTo=BLACK;
                    if(belongsTo==WHITE) belongsTo=VOID;
                }
                if(board[x][y+1]==WHITE)
                {
                    if(belongsTo==GRID) belongsTo=WHITE;
                    if(belongsTo==BLACK) belongsTo=VOID;
                }
            }
        }

        /* 统计该坐标上一格位置 */
        if(board[x][y-1]==VOID && count[x][y-1]==0){
            getVoidBlock(x,y-1);
        }
        else
        {
            if(belongsTo!=VOID)
            {
                if(board[x][y-1]==BLACK)
                {
                    if(belongsTo==GRID) belongsTo=BLACK;
                    if(belongsTo==WHITE) belongsTo=VOID;
                }
                if(board[x][y-1]==WHITE)
                {
                    if(belongsTo==GRID) belongsTo=WHITE;
                    if(belongsTo==BLACK) belongsTo=VOID;
                }
            }
        }

        /* 计算该坐标左一格位置 */
        if(board[x-1][y]==VOID && count[x-1][y]==0){
            getVoidBlock(x-1,y);
        }
        else
        {
            if(belongsTo!=VOID)
            {
                if(board[x-1][y]==BLACK)
                {
                    if(belongsTo==GRID) belongsTo=BLACK;
                    if(belongsTo==WHITE) belongsTo=VOID;
                }
                if(board[x-1][y]==WHITE)
                {
                    if(belongsTo==GRID) belongsTo=WHITE;
                    if(belongsTo==BLACK) belongsTo=VOID;
                }
            }
        }

        /* 计算该坐标右一格位置 */
        if(board[x+1][y]==VOID && count[x+1][y]==0){
            getVoidBlock(x+1,y);
        }
        else
        {
            if(belongsTo!=VOID)
            {
                if(board[x+1][y]==BLACK)
                {
                    if(belongsTo==GRID) belongsTo=BLACK;
                    if(belongsTo==WHITE) belongsTo=VOID;
                }
                if(board[x+1][y]==WHITE)
                {
                    if(belongsTo==GRID) belongsTo=WHITE;
                    if(belongsTo==BLACK) belongsTo=VOID;
                }
            }
        }

        /** 以下的返回值只有最外面一层是实际意义的, 递归中的返回值不会被使用 **/
        if(belongsTo==GRID) //全盘没有棋子时
        {
            return 0;
        }
        else return belongsTo;
    }
    else return 0;
}

void Judgment::init_getVoidBlock(int x,int y)
{
    on_off = false;
    int temp = getVoidBlock(x,y);

    /** 以下类似填子工作在本方的空上填满自己的子 **/
    if(temp == BLACK)
    {
        vector<coordinate>::iterator iter;
        for(iter=tempSeries.begin(); iter!=tempSeries.end(); iter++)
        {
            board[iter->first][iter->second] = BLACK;
        }
    }
    if(temp == WHITE)
    {
        vector<coordinate>::iterator iter;
        for(iter=tempSeries.begin(); iter!=tempSeries.end(); iter++)
        {
            board[iter->first][iter->second] = WHITE;
        }
    }
}

bool Judgment::writeBoard(const int o_board[][DIMENSION], const char* fileName)
{
    FILE *pFile;
    pFile = fopen ( fileName , "wb" );

    //that's the way how to write 2D-array to a bin file
    for(int i=0; i<DIMENSION; i++)
    {
        //everytime write a -row- of board to file
        fwrite (o_board[i] , sizeof(int) , sizeof(o_board[i])/sizeof(int) , pFile);
    }
    fclose (pFile);
    return true;
}

bool Judgment::readBoard(int i_board[][DIMENSION], const char* fileName)
{
    FILE *pFile;
    long lSize;
    int* buffer;
    size_t result;

    pFile = fopen ( fileName , "rb" );
    if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

    // obtain file size:
    fseek (pFile , 0 , SEEK_END);
    lSize = ftell (pFile);
    rewind (pFile);

    // allocate memory to contain the whole file:
    buffer = (int*) malloc (lSize);
    if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

    // copy the file into the buffer:
    result = fread (buffer,sizeof(int),lSize/sizeof(int),pFile);
    //if (result != lSize/sizeof(int)) {fputs ("Reading error",stderr); exit (3);}

    /* the whole file is now loaded in the memory buffer. */

    // terminate
    fclose (pFile);

    //read buffer into board[][]
    assert(result == DIMENSION*DIMENSION);
    for(int y=0; y<DIMENSION; y++)
    {
        for(int x=0; x<DIMENSION; x++)
        {
            i_board[x][y] = buffer[DIMENSION*x + y]; //注意这里x和y的关系, bin file中是一列一列储存的
        }
    }

    free (buffer);
    return true;
}

float Judgment::getInfluenceValue(int delta_x, int delta_y)
{
    switch(delta_x)
    {
        case 0:
        {
            switch(delta_y)
            {
                case 0: return 45.2;
                case 1: return 11.3;
                case 2: return 5.6;
                case 3: return 2.8;
                case 4: return 1.4;
            }
        }
        case 1:
        {
            switch(delta_y)
            {
                case 0: return 11.3;
                case 1: return 8;
                case 2: return 5;
                case 3: return 2.6;
                case 4: return 1.3;
            }
        }
        case 2:
        {
            switch(delta_y)
            {
                case 0: return 5.6;
                case 1: return 5;
                case 2: return 4;
                case 3: return 2.3;
                case 4: return 1.2;
            }
        }
        case 3:
        {
            switch(delta_y)
            {
                case 0: return 2.8;
                case 1: return 2.6;
                case 2: return 2.3;
                case 3: return 2.3;
                case 4: return 1.1;
            }
        }
        case 4:
        {
            switch(delta_y)
            {
                case 0: return 1.4;
                case 1: return 1.3;
                case 2: return 1.2;
                case 3: return 1.1;
                case 4: return 1.0;
            }
        }
    }
    return 0; //error
}

//这个函数中的数据只针对19路而设定
inline float Judgment::getInfluenceCoefficient(int x, int y)
{
    //到(10,10)的距离, 不是2点间的距离, 简化计算
    int distance = (abs(x-10) > abs(y-10) ? abs(x-10) : abs(y-10));

    if(distance >= 7)
    {
        return 1.0 - (float(distance-7) * 0.2);
    }
    else
    {
        return 1.0 - (float(7-distance) * 0.1);
    }
}

void Judgment::singleInfluence(int color, int x, int y)
{
    float k = getInfluenceCoefficient(x,y); //加权系数

    //确定边界
    int x_plus = D; int x_minus = D;
    int y_plus = D; int y_minus = D;
    if(x+D > DIMENSION-2) x_plus = DIMENSION-2 - x;
    if(x-D < 1)           x_minus = x - 1;
    if(y+D > DIMENSION-2) y_plus = DIMENSION-2 - y;
    if(y-D < 1)           y_minus = y - 1;

    //添加辐射值
    register int i,j;
    //确定--象限
    for(i=0; i<x_minus+1; i++)
    {
        for(j=1; j<y_minus+1; j++)
        {
            influence[x-i][y-j] += k * color * getInfluenceValue(i,j);
        }
    }
    //确定-+象限
    for(i=1; i<x_minus+1; i++)
    {
        for(j=0; j<y_plus+1; j++)
        {
            influence[x-i][y+j] += k * color * getInfluenceValue(i,j);
        }
    }
    //确定++象限
    for(i=0; i<x_plus+1; i++)
    {
        for(j=1; j<y_plus+1; j++)
        {
            influence[x+i][y+j] += k * color * getInfluenceValue(i,j);
        }
    }
    //确定+-象限
    for(i=1; i<x_plus+1; i++)
    {
        for(j=0; j<y_minus+1; j++)
        {
            influence[x+i][y-j] += k * color * getInfluenceValue(i,j);
        }
    }
    //确定原点的值, 取决于气数
    /** 棋子本身对自己的影响值有必要性, 但是取值待斟酌 **/
    if(board[x+1][y] == VOID) influence[x][y] += k * color * getInfluenceValue(2,0);
    if(board[x-1][y] == VOID) influence[x][y] += k * color * getInfluenceValue(2,0);
    if(board[x][y+1] == VOID) influence[x][y] += k * color * getInfluenceValue(0,2);
    if(board[x][y-1] == VOID) influence[x][y] += k * color * getInfluenceValue(0,2);
}

void Judgment::influenceCalculate(const int temp_board[][DIMENSION])
{
    for(register int i=0; i<DIMENSION-1; i++)
    {
        for(register int j=0; j<DIMENSION-1; j++)
        {
            influence[i][j] = 0.0;
        }
    }

    for(register int i=1; i<DIMENSION-1; i++)
    {
        for(register int j=1; j<DIMENSION-1; j++)
        {
            if(temp_board[i][j] == BLACK) singleInfluence(BLACK,i,j);
            else if(temp_board[i][j] == WHITE) singleInfluence(WHITE,i,j);
        }
    }
}

void Judgment::judgment_influenceCalc(int temp_board[][DIMENSION])
{
    //获得辐射模型模拟出来的数据
    influenceCalculate(temp_board);
    //对数据进行分析
    for(register int x=1; x<DIMENSION-1; x++)
    {
        for(register int y=1; y<DIMENSION-1; y++)
        {
            //黑
            if(temp_board[x][y] == BLACK && checked[x][y] == 0)
            {
                if(influence[x][y] < -BOUND)
                {
                    bool if_all = true;

                    //获得相关棋串, 检查是不是棋串所有子的值都相反
                    init_getBlock(x,y);

                    vector<coordinate>::iterator iter;
                    for(iter=tempSeries.begin(); iter!=tempSeries.end()&&if_all==true; iter++)
                    {
                        if(influence[iter->first][iter->second] > -BOUND) if_all = false;
                    }

                    //如果if_all==true 则继续以下步骤
                    if(if_all == true)
                    {
                        //检查该棋串相邻空位处的值
                        for(iter=tempSeries.begin(); iter!=tempSeries.end()&&if_all==true; iter++)
                        {
                            if(temp_board[iter->first + 1][iter->second] == VOID)
                                if(influence[iter->first + 1][iter->second] > 0) if_all = false;
                            if(temp_board[iter->first - 1][iter->second] == VOID)
                                if(influence[iter->first - 1][iter->second] > 0) if_all = false;
                            if(temp_board[iter->first][iter->second + 1] == VOID)
                                if(influence[iter->first][iter->second + 1] > 0) if_all = false;
                            if(temp_board[iter->first][iter->second - 1] == VOID)
                                if(influence[iter->first][iter->second - 1] > 0) if_all = false;
                        }
                    }

                    //如果if_all==true 则判定棋串为死棋, 从board上移除
                    if(if_all == true)
                    {
                        for(iter=tempSeries.begin(); iter!=tempSeries.end(); iter++)
                        {
                            //需要确保执行过copyBoard()函数, board数据正确
                            board[iter->first][iter->second] = VOID;
                        }
                    }
                }
            }
            //白
            else if(temp_board[x][y] == WHITE && checked[x][y] == 0)
            {
                if(influence[x][y] > BOUND)
                {
                    bool if_all = true;

                    //获得相关棋串, 检查是不是棋串所有子的值都相反
                    init_getBlock(x,y);

                    vector<coordinate>::iterator iter;
                    for(iter=tempSeries.begin(); iter!=tempSeries.end()&&if_all==true; iter++)
                    {
                        if(influence[iter->first][iter->second] < BOUND) if_all = false;
                    }

                    //如果if_all==true 则继续以下步骤
                    if(if_all == true)
                    {
                        //检查该棋串相邻空位处的值
                        for(iter=tempSeries.begin(); iter!=tempSeries.end()&&if_all==true; iter++)
                        {
                            if(temp_board[iter->first + 1][iter->second] == VOID)
                                if(influence[iter->first + 1][iter->second] < 0) if_all = false;
                            if(temp_board[iter->first - 1][iter->second] == VOID)
                                if(influence[iter->first - 1][iter->second] < 0) if_all = false;
                            if(temp_board[iter->first][iter->second + 1] == VOID)
                                if(influence[iter->first][iter->second + 1] < 0) if_all = false;
                            if(temp_board[iter->first][iter->second - 1] == VOID)
                                if(influence[iter->first][iter->second - 1] < 0) if_all = false;
                        }
                    }

                    //如果if_all==true 则判定棋串为死棋, 从board上移除
                    if(if_all == true)
                    {
                        for(iter=tempSeries.begin(); iter!=tempSeries.end(); iter++)
                        {
                            //需要确保执行过copyBoard()函数, board数据正确
                            temp_board[iter->first][iter->second] = VOID;
                        }
                    }
                }
            }
        }
    } //目前进行到这里通过测试可以得出结论:
      //更适合进行布局以及中盘之前的形势判断
      //可以进行粗糙的形势判断, 但是对于就算边角十分简单的死活出错几率很高
      //方案一: 在此之前先进行涉及所有棋块的绝对的死活判定, 去除肯定死的棋子
}

void Judgment::getBlock(int x, int y)
{
    coordinate coo;
    int current = board[x][y]; // 要计算的位置的棋子状况, 只可能是-1或1

    if (!on_off){ //静态变量归零代码
        for (register int i=1;i<DIMENSION-1;i++){
            for (register int j=1;j<DIMENSION-1;j++){
                count[i][j]=0;
            }
        }
        tempSeries.clear(); //静态变量vector<pair<int,int>>的清零工作
        on_off = true; //开关关闭, 因为递归时不需要归零
    }

    count[x][y] = 1; //将目前的位置标记为计算过的位置
    checked[x][y] = 1;

    /* 棋块获取 */
    coo.first=x; coo.second=y;
    tempSeries.push_back(coo); //将坐标压入棋块容器中

    /* 统计该坐标下一格位置 */
    if(board[x][y+1]==current && count[x][y+1]==0){
        getBlock(x,y+1);
    }

    /* 统计该坐标上一格位置 */
    if(board[x][y-1]==current && count[x][y-1]==0){
        getBlock(x,y-1);
    }

    /* 计算该坐标左一格位置 */
    if(board[x-1][y]==current && count[x-1][y]==0){
        getBlock(x-1,y);
    }

    /* 计算该坐标右一格位置 */
    if(board[x+1][y]==current && count[x+1][y]==0){
        getBlock(x+1,y);
    }
}

void Judgment::init_getBlock(int x, int y)
{
    on_off = false;
    getBlock(x,y); //获得零时棋块变量数据
}

void Judgment::identifyPublic(const int original_board[][DIMENSION])
{
    int color;

    for(register int i=1; i<DIMENSION-1; i++)
    {
        for(register int j=1; j<DIMENSION-1; j++)
        {
            color = VOID;

            //获取在原棋局中为空位, 形势判断后为目数的点位
            if( board[i][j]!=VOID && original_board[i][j]==VOID )
            {
                //上
                switch(board[i][j-1])
                {
                    case BLACK: { if(color==WHITE) {board[i][j]=VOID;}
                                  else {color = BLACK;} break;}
                    case WHITE: { if(color==BLACK) {board[i][j]=VOID;}
                                  else {color = WHITE;} break;}
                }
                //下
                switch(board[i][j+1])
                {
                    case BLACK: { if(color==WHITE) {board[i][j]=VOID;}
                                  else {color = BLACK;} break;}
                    case WHITE: { if(color==BLACK) {board[i][j]=VOID;}
                                  else {color = WHITE;} break;}
                }
                //左
                switch(board[i-1][j])
                {
                    case BLACK: { if(color==WHITE) {board[i][j]=VOID;}
                                  else {color = BLACK;} break;}
                    case WHITE: { if(color==BLACK) {board[i][j]=VOID;}
                                  else {color = WHITE;} break;}
                }
                //右
                switch(board[i+1][j])
                {
                    case BLACK: { if(color==WHITE) {board[i][j]=VOID;}
                                  else {color = BLACK;} break;}
                    case WHITE: { if(color==BLACK) {board[i][j]=VOID;}
                                  else {color = WHITE;} break;}
                }
            }
        }
    }
}
